package utils

import (
	"context"
	"errors"
	"git.mycaigou.com/gfyx/common/cache"
	"git.myscrm.cn/golang/stark/v4"
	"github.com/parnurzeal/gorequest"
)

const (
	DataServiceHOST = "data_service_host"

	DataServiceTokenCacheKey = "gfyx:data_service:token"

	DataServiceTokenUri        = "data_service_token_uri"
	DataServiceTokenExpireTime = "data_service_token_expire_time"
	DataServiceAppId           = "data_service_appid"
	DataServiceAppKey          = "data_service_appkey"
)

type DataServiceClient struct {
	client *HttpClientTool
}

// NewDataServiceClient
// 供方SaaS自建数据服务http client工具类
func NewDataServiceClient() *DataServiceClient {
	return &DataServiceClient{
		client: New(),
	}
}

// Get
// 搜索服务Get请求
func (c *DataServiceClient) Get(ctx context.Context, path string, params map[string]interface{}) *DataServiceClient {
	url := stark.Configer.(stark.ApolloConfigerIface).GetStringValue(DataServiceHOST, "") + path
	url = JoinQueryStr(url, params)
	header := c.setHeader(ctx, map[string]string{})
	c.client = c.client.Get(ctx, url, header)
	return c
}

// Post
// 搜索服务Post请求
func (c *DataServiceClient) Post(ctx context.Context, path string, params map[string]interface{}, header map[string]string) *DataServiceClient {
	url := stark.Configer.(stark.ApolloConfigerIface).GetStringValue(DataServiceHOST, "") + path
	header = c.setHeader(ctx, header)
	c.client = c.client.Post(ctx, url, params, header)
	return c
}

// EndStruct
// convert interface(v) to struct
func (c *DataServiceClient) EndStruct(v interface{}) (gorequest.Response, []byte, []error) {
	return c.client.EndStruct(v)
}

func (c *DataServiceClient) setHeader(ctx context.Context, header map[string]string) map[string]string {
	if header == nil {
		header = map[string]string{}
	}
	token, err := c.GetToken(ctx)
	if err != nil {
		stark.Logger.Errorf(ctx, "获取token失败，err:%+v", err)
	}
	header["authorization"] = "bearer " + token
	header["Content-Type"] = "application/json"
	return header
}

type DataServiceTokenResult struct {
	Success bool   `json:"success"`
	Data    string `json:"data"`
	Message string `json:"message"`
}

func (c *DataServiceClient) GetToken(ctx context.Context) (string, error) {
	//缓存key拼接
	cacheKey := DataServiceTokenCacheKey
	//读缓存
	redisClient, _ := cache.Redis()
	token, err := redisClient.Get(ctx, cacheKey)
	if err != nil {
		stark.Logger.Errorf(ctx, "数据服务,读缓存失败，err: %+v", err)
		return "", err
	} else if token != "" {
		return token, nil
	}

	//组装header
	header := map[string]string{}
	appID := stark.Configer.(stark.ApolloConfigerIface).GetStringValue(DataServiceAppId, "")
	appKey := stark.Configer.(stark.ApolloConfigerIface).GetStringValue(DataServiceAppKey, "")

	//发起请求
	var result DataServiceTokenResult
	url := stark.Configer.(stark.ApolloConfigerIface).GetStringValue(DataServiceHOST, "") + stark.Configer.(stark.ApolloConfigerIface).GetStringValue(DataServiceTokenUri, "")
	url += "?app_id=" + appID + "&app_key=" + appKey
	client := c.client.Get(ctx, url, header)

	//处理请求结果
	resp, _, errs := client.EndStruct(&result)

	if len(errs) > 0 {
		stark.Logger.Errorf(ctx, "数据服务get token失败，err:%+v", errs)
		return "", errs[0]
	}
	stark.Logger.Infof(ctx, "数据服务get token, response: %+v, data:%+v", resp, result)
	if result.Success == false {
		stark.Logger.Errorf(ctx, "数据服务get token失败，result:%+v", result)
		return "", errors.New("获取数据服务token失败")
	}
	if result.Data == "" {
		stark.Logger.Errorf(ctx, "数据get token 失败，token为空")
		return "", errors.New("获取数据服务token失败")
	}

	//设置缓存
	expireTime := stark.Configer.(stark.ApolloConfigerIface).GetIntValue(DataServiceTokenExpireTime, 1800)
	if expireTime <= 0 {
		expireTime = 7200
	}
	_, errSetCache := redisClient.Set(ctx, cacheKey, result.Data, true, expireTime)
	if errSetCache != nil {
		stark.Logger.Errorf(ctx, "数据服务 set token 缓存失败，err:%+v", err)
	}
	return result.Data, nil
}
